﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace CTOOLS
{
    /// <summary>
    /// 动态创建委托
    /// </summary>
    public class CreateDelegateHelper
    {
        /// <summary>
        /// 创建委托
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="methodName"></param>
        /// <param name="autoinstance"></param>
        /// <returns></returns>
        public static T CreateDelegate<T>(Type type, string methodName, object instance, bool autoinstance) where T : class
        {
            var method = judgeMetehod(type, methodName);
            if (method == null)
                throw new ArgumentNullException("当前类" + type.Name + "  方法名：" + methodName + " 不存在！(可被访问) ");
            return CreateDelegate<T>(type, method, instance, autoinstance);
        }

        public static T CreateDelegate<T>(Type instanceType, MethodInfo methodInfo, object instance, bool autoinstance) where T : class
        {
            var param = methodInfo.GetParameters();
            ParameterExpression[] paramexpressions = new ParameterExpression[param.Length];
            List<ParameterExpression> paramexpressionsValue = new List<ParameterExpression>();
            for (int i = 0; i < paramexpressions.Length; i++)
            {
                var paramsName = Expression.Parameter(param[i].ParameterType, param[i].Name);
                paramexpressions[i] = paramsName;
                paramexpressionsValue.Add(paramsName);
            }
            Expression expression = null;
            if (methodInfo.IsStatic)
                expression = Expression.Call(null, methodInfo, paramexpressionsValue.ToArray());
            else
            {
                if (autoinstance)
                    expression = Expression.Call(Expression.New(instanceType), methodInfo, paramexpressionsValue.ToArray());
                else
                    expression = Expression.Call(Expression.Constant(instance), methodInfo, paramexpressionsValue.ToArray());
            }
            if (!methodInfo.ReturnType.Equals(typeof(void)))
            {
                expression = Expression.Convert(expression, methodInfo.ReturnType);
            }
            LambdaExpression lambdaExpression = Expression.Lambda(expression, paramexpressions);
            Delegate @delegate = lambdaExpression.Compile();
            return @delegate as T;
        }

        public static T CreateDelegate<T>(Type type, string methodName, bool autoinstance = false) where T : class
        {
            return CreateDelegate<T>(type, methodName, null, autoinstance);
        }
        /// <summary>
        /// 动态创建委托
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="instance"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static T CreateDelegate<T>(object instance, string methodName, bool autoinstance = false) where T : class
        {
            return CreateDelegate<T>(instance.GetType(), methodName, instance, autoinstance);
        }

        /// <summary>
        /// 判断是否有方法
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static MethodInfo judgeMetehod(Type type, string methodName)
        {
            var metehodinfo = type.GetMethod(methodName);
            return metehodinfo;
        }
    }
}